package com.cinc.mdm.modules.materialCodeRule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cinc.mdm.modules.materialCodeRule.entity.MdmMaterialCodeRule;
import com.cinc.mdm.modules.materialCodeRule.enums.MaterialCodeRulePartEnum;
import com.cinc.mdm.modules.materialCodeRule.mapper.MdmMaterialCodeRuleMapper;
import com.cinc.mdm.modules.materialCodeRule.service.IMdmMaterialCodeRuleService;
import com.cinc.mdm.modules.sequence.enums.SeqTypeEnum;
import com.cinc.mdm.modules.sequence.service.IMdmSequenceService;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 物料自动编码规则
 * @Author: jeecg-boot
 * @Date: 2023-08-31
 * @Version: V1.0
 */
@Service
public class MdmMaterialCodeRuleServiceImpl extends ServiceImpl<MdmMaterialCodeRuleMapper, MdmMaterialCodeRule> implements IMdmMaterialCodeRuleService {

    @Autowired
    private IMdmSequenceService mdmSequenceService;

    @Override
    public boolean add(MdmMaterialCodeRule entity) {

        checkMaterialCodeRepeat(entity);
        return save(entity);
    }

    @Override
    public boolean edit(MdmMaterialCodeRule entity) {

        checkMaterialCodeRepeat(entity);
        return updateById(entity);
    }

    private void checkMaterialCodeRepeat(MdmMaterialCodeRule entity) {
        if ("1".equals(entity.getEnableFlag())) {
            LambdaQueryWrapper<MdmMaterialCodeRule> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MdmMaterialCodeRule::getEnableFlag, "1");
            if (oConvertUtils.isNotEmpty(entity.getId())) {
                queryWrapper.ne(MdmMaterialCodeRule::getId, entity.getId());
            }
            int count = baseMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new RuntimeException("物料编码规则只能有一项启用");
            }
        }
    }

    @Override
    public String generateMaterialCode(String materialType, String materialClass) {
        LocalDate now = LocalDate.now();
        MdmMaterialCodeRule codeRule = getCodeRuleValid();
        int year = codeRule.getYear() == null ? 0 : codeRule.getYear();
        int month = codeRule.getMonth() == null ? 0 : codeRule.getMonth();
        int day = codeRule.getDay() == null ? 0 : codeRule.getDay();
        List<String> partList = new ArrayList<>();
        partList.add(codeRule.getPart01());
        partList.add(codeRule.getPart02());
        partList.add(codeRule.getPart03());
        partList.add(codeRule.getPart04());
        partList.add(codeRule.getPart05());
        //
        long dateCount = partList.stream().filter(part -> MaterialCodeRulePartEnum.TYPE03.getCode().equals(part)).count();
        //
        StringBuilder seqValBuilder = new StringBuilder();
        partList.forEach(part -> {
            if(MaterialCodeRulePartEnum.TYPE01.getCode().equals(part)){
                seqValBuilder.append(oConvertUtils.isEmpty(materialType) ? "" : materialType+"-");
            }else if(MaterialCodeRulePartEnum.TYPE02.getCode().equals(part)){
                seqValBuilder.append(oConvertUtils.isEmpty(materialClass) ? "" : materialClass+"-");
            }else if(MaterialCodeRulePartEnum.TYPE04.getCode().equals(part)){
                seqValBuilder.append(oConvertUtils.isEmpty(codeRule.getFixed()) ? "" : codeRule.getFixed() +"-");
            }else{
                //
            }
        });
        String seqVal = oConvertUtils.isEmpty(seqValBuilder.toString()) ? "-" : seqValBuilder.toString().substring(0, seqValBuilder.length()-1);
        //
        StringBuilder codeBuilder = new StringBuilder();
        boolean seqNoResetFlag = false;
        int seqNo = 0;
        for (String part : partList) {
            if (part.equals(MaterialCodeRulePartEnum.TYPE01.getCode())) {
                if(oConvertUtils.isEmpty(materialType)){
                    throw new RuntimeException("物料编码生成失败，物料类型不能为空");
                }
                codeBuilder.append(materialType);
            } else if (part.equals(MaterialCodeRulePartEnum.TYPE02.getCode())) {
                if(oConvertUtils.isEmpty(materialClass)){
                    throw new RuntimeException("物料编码生成失败，物料分类不能为空");
                }
                codeBuilder.append(materialClass);
            } else if (part.equals(MaterialCodeRulePartEnum.TYPE03.getCode())) {
                codeBuilder.append(now.format(DateTimeFormatter.ofPattern(codeRule.getDateFmt())));
            } else if (part.equals(MaterialCodeRulePartEnum.TYPE04.getCode())) {
                codeBuilder.append(codeRule.getFixed() == null ? "" : codeRule.getFixed());
            } else if (part.equals(MaterialCodeRulePartEnum.TYPE05.getCode())) {
                if (dateCount > 0) {
                    if ((codeRule.getDateFmt().contains("y") && now.getYear() != year)
                            || (codeRule.getDateFmt().contains("M") && now.getMonthValue() != month)
                            || (codeRule.getDateFmt().contains("d") && now.getDayOfMonth() != day)) {
                        // 序列号重置
                        if (!seqNoResetFlag) {
                            mdmSequenceService.resetSeqNo(SeqTypeEnum.TYPE01.getCode(), seqVal);
                        }
                    }
                }
                if (!seqNoResetFlag) {
                    seqNo = mdmSequenceService.nextSeqNo(SeqTypeEnum.TYPE01.getCode(), seqVal);
                    seqNoResetFlag = true;
                }
                codeBuilder.append(String.format("%0" + codeRule.getSeqLength() + "d", seqNo));
            } else {
                //
            }
        }
        // 更新编码规则年月日
        MdmMaterialCodeRule codeRuleModify = new MdmMaterialCodeRule();
        codeRuleModify.setId(codeRule.getId());
        codeRuleModify.setYear(now.getYear());
        codeRuleModify.setMonth(now.getMonthValue());
        codeRuleModify.setDay(now.getDayOfMonth());
        baseMapper.updateById(codeRuleModify);

        return codeBuilder.toString();
    }

    /**
     * 编码规则定义校验
     */
    private MdmMaterialCodeRule getCodeRuleValid() {
        LambdaQueryWrapper<MdmMaterialCodeRule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MdmMaterialCodeRule::getEnableFlag, "1");
        List<MdmMaterialCodeRule> codeRuleList = baseMapper.selectList(queryWrapper);
        if (oConvertUtils.listIsEmpty(codeRuleList)) {
            throw new RuntimeException("物料编码规则未定义");
        }
        List<MdmMaterialCodeRule> enableList = codeRuleList.stream().filter(rule -> "1".equals(rule.getEnableFlag())).collect(Collectors.toList());
        if (oConvertUtils.listIsEmpty(enableList)) {
            throw new RuntimeException("物料编码规则未启用");
        }
        if (enableList.size() > 1) {
            throw new RuntimeException("物料编码规则只能有一项启用");
        }
        MdmMaterialCodeRule codeRule = enableList.get(0);
        List<String> partList = Arrays.asList(codeRule.getPart01(), codeRule.getPart02(), codeRule.getPart03(), codeRule.getPart04(), codeRule.getPart05());
        long partCount = partList.stream().filter(part -> MaterialCodeRulePartEnum.TYPE05.getCode().equals(part)).count();
        if (partCount == 0) {
            throw new RuntimeException("物料编码规则必须设置自增序列");
        }
        if (codeRule.getSeqLength() == null || codeRule.getSeqLength() <= 0) {
            throw new RuntimeException("物料编码规则必须设置序列号长度");
        }
        partCount = partList.stream().filter(part ->
                MaterialCodeRulePartEnum.TYPE03.getCode().equals(part) && oConvertUtils.isEmpty(codeRule.getDateFmt())
        ).count();
        if (partCount > 0) {
            throw new RuntimeException("物料编码规则设置了日期，必须指定日期格式");
        }

        return codeRule;
    }
}
